package bean;


import nsl.com.util.excel.basic.UtilExcelCell;
import nsl.com.util.excel.basic.UtilExcelWorkBookAndSheet;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import string.UtilString;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * Description: domain factory
 * Created by 4790K_NSL on 2017/5/4.
 */
public class UtilBeanFactory {


    static public <T> List<T> buildExcelBeanList(String excelFile,String sheetName, Class<T> clazz) throws IllegalAccessException, IOException, InstantiationException, InvalidFormatException {
        return buildExcelBeanList(excelFile,sheetName,clazz,0);
    }

    static public <T> List<T> buildExcelBeanList(String excelFile,String sheetName, Class<T> clazz, int headIndex) throws IllegalAccessException, IOException, InstantiationException, InvalidFormatException {
        Workbook workbook= UtilExcelWorkBookAndSheet.getWorkbook(excelFile);
        return buildExcelBeanList(workbook,sheetName,clazz,headIndex);
    }

    static public <T> List<T> buildExcelBeanList(Workbook workbook,String sheetName, Class<T> clazz) throws IllegalAccessException, UnsupportedEncodingException, InstantiationException {
       return buildExcelBeanList(workbook,sheetName,clazz,0);
    }

    static public <T> List<T> buildExcelBeanList(Workbook workbook,String sheetName, Class<T> clazz, int headIndex) throws IllegalAccessException, UnsupportedEncodingException, InstantiationException {
        Sheet sheet=workbook.getSheet(sheetName);
        return buildExcelBeanList(sheet,clazz,headIndex);
    }

    static public <T> List<T> buildExcelBeanList(Sheet sheet,Class<T> clazz) throws IllegalAccessException, UnsupportedEncodingException, InstantiationException {
        return buildExcelBeanList(sheet,clazz,0);
    }
    /** 从sheet 生成 Bean Of T
     * @param sheet
     * @param clazz
     * @param headIndex 表头
     * @param <T>
     * @return
     * @throws IllegalAccessException
     * @throws UnsupportedEncodingException
     * @throws InstantiationException
     */
    static public <T> List<T> buildExcelBeanList(Sheet sheet,Class<T> clazz,int headIndex) throws IllegalAccessException, UnsupportedEncodingException, InstantiationException {
        List<T> tList=new ArrayList<>();
        Map<String,Field> fieldNameMap=UtilBeanInfo.getFieldNameMapOfLowCase(clazz);
        Row headRow=sheet.getRow(headIndex);
        Map<String,Integer> beanFieldMap=getExcelBeanFieldMapFromHeadRow(headRow,clazz);

        for (int i = headIndex+1; i <= sheet.getLastRowNum(); i++) {
            Row valueRow = sheet.getRow(i);
            if (valueRow == null) {
                continue;
            }
            T t = buildExcelBeanFromValueRow(valueRow, clazz, fieldNameMap, beanFieldMap);
            tList.add(t);
        }
        return tList;
    }

    static public <T> T  buildExcelBeanFromValueRow(Row valueRow, Class<T> clazz, Map<String,Field> fieldNameMap,Map<String,Integer> beanFieldMap) throws IllegalAccessException, InstantiationException, UnsupportedEncodingException {
        T t=clazz.newInstance();
        Set<String> fieldNameSet=beanFieldMap.keySet();
        for (String fieldName : fieldNameSet) {
            Integer columnIndex=beanFieldMap.get(fieldName);
            String stringValue= UtilExcelCell.getCellStringValue(valueRow.getCell(columnIndex));
            //System.out.println(fieldName+" : "+stringValue);
            Field field=fieldNameMap.get(fieldName);
            setSimpleFieldValueByString(t,field,stringValue);
        }
        //System.out.println(t);
        return t;
    }

    /**读取Excel表头行，返回 Map<fieldName,columnIndex),其中fieldName都为小写字母
     * @param headrow 表头，标识了，domain 的属性名称
     * @param clazz 拟转换的class
     * @return
     */
    static public Map<String,Integer> getExcelBeanFieldMapFromHeadRow(Row headrow, Class clazz){
        Set<String> fieldNames=UtilBeanInfo.getFieldNameSet(clazz);
        UtilString.toLowerCase(fieldNames);

        //获取 filedName,columnIndex　组成的map.
        Map<String,Integer> fieldMap=new HashMap<>();//<FieldName,columnIndx>
        for (Cell cell : headrow) {
            String headValue= UtilExcelCell.getCellStringValue(cell);
            if (headValue != null) {
                headValue=headValue.toLowerCase();
                if(fieldNames.contains(headValue)){
                    if(fieldMap.keySet().contains(headValue)){
                        throw new RuntimeException("表头属性有重复");
                    }else {
                        fieldMap.put(headValue,cell.getColumnIndex());
                    }
                }
            }
        }
        return fieldMap;
    }



    static public void setSimpleFieldValueByString(Object object,Field field,String s) throws IllegalAccessException, UnsupportedEncodingException {
        //System.out.println("-Nsl-:In UtilBeanFactory.setSimpleFieldValueByString(), object = " + object);
        //System.out.println("-Nsl-:In UtilBeanFactory.setSimpleFieldValueByString(),  field.getGenericType()= " + field.getGenericType());
       // System.out.println("-Nsl-:In UtilBeanFactory.setSimpleFieldValueByString(), s = " + s);
        
        field.setAccessible(true);
        if (s == null) {
            field.set(object,null);
            return;
        }

        String filedTypeName=field.getGenericType().toString().toLowerCase();

        filedTypeName=UtilString.getLastSubString(filedTypeName,".");
        //System.out.println("filedTypeName = "+ filedTypeName);

        if(!UtilBeanInfo.isSmpleField(field) && !filedTypeName.equalsIgnoreCase("byte[]")){
            throw new RuntimeException("field type: "+filedTypeName+" is not  simple.");
        }

        if(filedTypeName.equalsIgnoreCase("int") || filedTypeName.equalsIgnoreCase("integer") ){
            s=s.toLowerCase();
            //eg. 1.0 or 3.14 e 3(3.14 * 1000)
            if(s.indexOf(".")>=0 || s.indexOf("e")>=0){
                Double dValue=Double.parseDouble(s);
                Integer iValue=dValue.intValue();
                field.setInt(object,iValue);
            }else {
                field.setInt(object,Integer.parseInt(s));
            }
            return;
        }

        if(filedTypeName.equalsIgnoreCase("float")){
            field.setFloat(object,Float.parseFloat(s));
            return ;
        }

        if(filedTypeName.equalsIgnoreCase("double")){
            field.setDouble(object,Double.parseDouble(s));
            return ;
        }

        if(filedTypeName.equalsIgnoreCase("boolean")){
            field.setBoolean(object,Boolean.parseBoolean(s));
            return ;
        }

        if(filedTypeName.equalsIgnoreCase("char")){
            if(s.length()!=1){
                throw new RuntimeException("String: "+s+"can't convert to char.");
            }
            field.setChar(object,s.charAt(0));
            return ;
        }

        if(filedTypeName.equalsIgnoreCase("byte[]")){
            field.set(object,s.getBytes("UTF-8"));
            return ;
        }

        if(filedTypeName.equalsIgnoreCase("short")){
            field.setShort(object,Short.parseShort(s));
            return ;
        }

        if(filedTypeName.equalsIgnoreCase("string")){
            field.set(object,s);
            return ;
        }

        throw new RuntimeException("Filed: "+filedTypeName+" 无法识别");
    }
}
